package com.jinsp.startup_library;


import android.os.Looper;
import android.util.Log;

import com.jinsp.startup_library.sort.StartupTopologyResultBean;
import com.jinsp.startup_library.sort.StartupTopologySort;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

/**
 * Created by luoshuai on 2/25/22
 * <p>
 * 启动任务管理类，构建者
 */
public class StartupManager {

    private List<Startup<?>> startupList;
    private Executor startupExecutor;
    private StartupTopologyResultBean startupTopologyResultBean;
    private CountDownLatch mainThreadCountDownLatch;

    public List<Startup<?>> getStartupList() {
        return startupList;
    }

    public Executor getStartupExecutor() {
        return startupExecutor;
    }

    /**
     * 执行启动任务
     *
     * @return 当前对象
     */
    public StartupManager start() {
        if (Looper.getMainLooper().getThread() != Thread.currentThread()) {
            throw new RuntimeException("需要在主线程中开启");
        }
        //排序启动任务
        startupTopologyResultBean = StartupTopologySort.sort(startupList);
        if (startupTopologyResultBean != null) {
            List<Startup<?>> startupSortList = startupTopologyResultBean.getStartupSortList();
            for (Startup<?> startup : startupSortList) {
                StartupRunnable startupRunnable = new StartupRunnable(startup, this);
                if (startup.isOnMainThread()) {
                    startupRunnable.run();
                } else {
                    startupExecutor.execute(startupRunnable);
                }
            }
        }
        return this;
    }

    /**
     * 主线程等待
     */
    public void needMainThreadWait() {
        if (mainThreadCountDownLatch != null && startupTopologyResultBean != null) {
            try {
                mainThreadCountDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 通知下一个启动任务运行
     *
     * @param currentStartup 当前启动任务
     */
    public void notifyNextStartupRunning(Startup<?> currentStartup) {
        if (startupTopologyResultBean == null) {
            return;
        }
        //通知主线程运行
        if (!currentStartup.isOnMainThread() && currentStartup.needMainThreadWait()) {
            mainThreadCountDownLatch.countDown();
        }
        Map<Class<? extends Startup<?>>, List<Class<? extends Startup<?>>>> nextStartupMap = startupTopologyResultBean.getNextStartupMap();
        Map<Class<? extends Startup<?>>, Startup<?>> startupMap = startupTopologyResultBean.getStartupMap();
        List<Class<? extends Startup<?>>> nextStartupList = nextStartupMap.get(currentStartup.getClass());
        if (nextStartupList != null) {
            for (Class<? extends Startup<?>> nextStartupClass : nextStartupList) {
                Startup<?> nextStartup = startupMap.get(nextStartupClass);
                nextStartup.notifyAndRunning();
            }
        }
    }

    public static class Builder {

        private Executor startupExecutor;       //启动任务线程池
        private final List<Startup<?>> startupList = new ArrayList<>();   //保存需要启动的任务

        /**
         * 设置任务执行线程池
         *
         * @param startupExecutor 线程池
         * @return 当前对象
         */
        public Builder setStartupExecutor(Executor startupExecutor) {
            this.startupExecutor = startupExecutor;
            return this;
        }

        /**
         * 添加启动任务
         *
         * @param startup 启动任务
         * @return 当前对象
         */
        public Builder addStartup(Startup<?> startup) {
            startupList.add(startup);
            return this;
        }

        /**
         * 添加启动任务列表
         *
         * @param startups 启动任务列表
         * @return 当前对象
         */
        public Builder addStartup(List<Startup<?>> startups) {
            if (startups != null && startups.size() > 0) {
                startupList.addAll(startups);
            }
            return this;
        }

        public StartupManager build() {
            if (startupExecutor == null) {
                startupExecutor = Executors.newCachedThreadPool();
            }
            int needMainThreadWaitCount = 0;
            for (Startup<?> startup : startupList) {
                if (!startup.isOnMainThread() && startup.needMainThreadWait()) {
                    needMainThreadWaitCount++;
                }
            }
            CountDownLatch mainThreadCountDownLatch = new CountDownLatch(needMainThreadWaitCount);
            StartupManager startupManager = new StartupManager();
            startupManager.startupExecutor = startupExecutor;
            startupManager.startupList = startupList;
            startupManager.mainThreadCountDownLatch = mainThreadCountDownLatch;
            return startupManager;
        }
    }
}
